#include "RoomGrid.hpp"
#include "Entity.h"

// This algorithm currently just renders every single tile of every room; it needs to be improved upon to only render those rooms that can be seen on screen
void RoomGrid::Render()
{
	/*list<Room>::const_iterator it;
	for(it = rooms.begin(); it != rooms.end(); ++it)
		for(int h = 0; h < it->h; ++h)
			for(int w = 0; w < it->w; ++w)
				for(int l = 0; l < it->tiles[h][w].size(); ++l)
					Entity::RenderImage((it->x1 + w) * TILE_DIMENSIONS, (it->y1 + h) * TILE_DIMENSIONS, it->tiles[h][w][l]);*/

	int width = (m_pEditorManager->m_pClipPlane->GetWidth() / 32) + 1;
	int height = (m_pEditorManager->m_pClipPlane->GetHeight() / 32) + 2;
	int startX = m_pEditorManager->m_pClipPlane->GetX() / 32;
	int startY = m_pEditorManager->m_pClipPlane->GetY() / 32;

	list<int>::const_iterator iter;
	for(int h = startY; h < height + startY && h < m_Tiles.size(); ++h)
		for(int w = startX; w < width + startX && w < m_Tiles[h].size(); ++w)
			for(iter = m_Tiles[h][w].begin(); iter != m_Tiles[h][w].end(); ++iter)
				Entity::RenderImage(w * TILE_DIMENSIONS, h * TILE_DIMENSIONS, (*iter), m_pEditorManager->m_pClipPlane);

}

void RoomGrid::BuildBackground(const Room& room)
{
	m_Tiles.reserve(room.h + 1);
	m_Tiles.resize(room.h + 1);
	for(int h = 0; h < room.h; ++h)
	{
		m_Tiles.reserve(room.w + 1);
		m_Tiles[h].resize(room.w + 1);
		for(int w = 0; w < room.w; ++w)
			for(int l = 0; l < room.tiles[h][w].size(); ++l)
				m_Tiles[h][w].push_back(room.tiles[h][w][l]);
	}

}
void RoomGrid::AddRoom(const Room& room)
{
	vector<GFXID> gfx = MapGen->GetGFXIDVector();

	int ignored = ImageManager->GetImageID("ignored_tile");
	for(int h = room.y1; (h < (room.h + room.y1)) && (h < m_Tiles.size()); ++h) // iterate through height of room + y
		for(int w = room.x1; (w < (room.w + room.x1)) && (w < m_Tiles[h].size()); ++w) // iterate through width of room + x
		{
			if((h < m_Tiles.size() && w < m_Tiles[h].size()) && (h-room.y1 < room.tiles.size() && w-room.x1 < room.tiles[h-room.y1].size())) // make sure we have a valid location
				for(int l = 0; l < room.tiles[h-room.y1][w-room.x1].size(); ++l) // iterate all layers
					if(room.tiles[h-room.y1][w-room.x1][l] != ignored) // don't add ignored tiles
					{
						// iterate through all of the gfxIDs and if we have a base GFXID, then clear the list and add it to the front.  otherwise, add it to the back
						bool addBack = true;
						for(vector<GFXID>::const_iterator it = gfx.begin(); it != gfx.end(); ++it)
							if(it->base == room.tiles[h-room.y1][w-room.x1][l])
								addBack = false;

						if(addBack)
							m_Tiles[h][w].push_back(room.tiles[h-room.y1][w-room.x1][l]); // finally, add the tile
						else
						{
							m_Tiles[h][w].clear();
							m_Tiles[h][w].push_front(room.tiles[h-room.y1][w-room.x1][l]);
						}
					}
			else
				Log->AddMessage("WARNING: RoomGrid::AddRoom attempted to add a tile that would have caused a subscript error"); // an invalid tile, throw a warning
		}

}

void RoomGrid::Render(bool nothing)
{
	// Get our vector of rooms to render that are on screen.
	vector<Room*> rooms = m_pEditorManager->m_pRoomManager->GetRoomsOnscreen(m_pEditorManager->m_pClipPlane);

	GameRectangle clip;
	clip.x = (double)m_pEditorManager->m_pClipPlane->GetX() / 32.0;
	clip.y = (double)m_pEditorManager->m_pClipPlane->GetY() / 32.0;
	clip.width = (double)m_pEditorManager->m_pClipPlane->GetWidth() / 32.0;
	clip.height = (double)m_pEditorManager->m_pClipPlane->GetHeight() / 32.0;

	// do a quick render of the background, but just render the other rooms in full
	// Iterate through all the rooms.
	//for(vector<Room*>::const_iterator it = rooms.begin(); it != rooms.end(); ++it)
	vector<Room*>::const_iterator it = rooms.begin();
	{
		GameRectangle loc;
		loc.width = (clip.width > (*it)->w) ? ((*it)->w) : (clip.width);
		loc.height = (clip.height > (*it)->h) ? ((*it)->h) : (clip.height);
		
		// If the rooms coordinates are larger than the clipping plane's than use the room's coordinates
		if((*it)->x1 > clip.x)
		{
			loc.x = (*it)->x1;

		}
		else
		{
			loc.x = clip.x;
			loc.width = abs((*it)->w + (*it)->x1 - clip.x);
			loc.width = (loc.width < clip.width) ? (loc.width) : (clip.width);
		}

		if((*it)->y1 > clip.y)
		{
			loc.y = (*it)->y1;
		}
		else
		{
			loc.y = clip.y;
			loc.height = abs((*it)->h + (*it)->y1 - clip.y);
			loc.height = (loc.height < clip.height) ? (loc.height) : (clip.height);
		}

		
		for(int h = loc.y + loc.height + 1; h >= loc.y; --h)
			for(int w = loc.x + loc.width; w >= loc.x; --w)
		//for(int h = loc.y; h < loc.y + loc.height; ++h)
		//	for(int w = loc.x; w < loc.x + loc.width; ++w)
			{
				if(h-loc.y < (*it)->tiles.size() && w-loc.x < (*it)->tiles[0].size())
					for(int l = 0; l < (*it)->tiles[h-loc.y][w-loc.x].size(); ++l)
					{
						int a = h - loc.y;
						int b = w - loc.x;
						Entity::RenderImage(w * TILE_DIMENSIONS, h * TILE_DIMENSIONS, (*it)->tiles[h-loc.y][w-loc.x][l], m_pEditorManager->m_pClipPlane);
					}
				//else
					//Log->AddMessage("RoomGrid::Render attempted to access a bad index");
			}
		

	}
	++it;

	// render the rest of the rooms normally, without clipping them at all
	for(it; it != rooms.end(); ++it)
	{
		for(int h = (*it)->y1 + (*it)->h; h >= (*it)->y1; --h)
			for(int w = (*it)->x1 + (*it)->w; w >= (*it)->x1; --w)
				if(h-(*it)->y1 < (*it)->tiles.size() && w-(*it)->x1 < (*it)->tiles[0].size())
					for(int l = 0; l < (*it)->tiles[h-(*it)->y1][w-(*it)->x1].size(); ++l)
						Entity::RenderImage(w * TILE_DIMENSIONS, h * TILE_DIMENSIONS, (*it)->tiles[h-(*it)->y1][w-(*it)->x1][l], m_pEditorManager->m_pClipPlane);
	}

}
/*void RoomGrid::Render(bool nothing)
{
	vector<Room*> rooms = m_pEditorManager->m_pRoomManager->GetRoomsOnscreen(m_pEditorManager->m_pClipPlane);
	// o -> original
	int ostartX = m_pEditorManager->m_pClipPlane->GetX() / 32;
	int ostartY = m_pEditorManager->m_pClipPlane->GetY() / 32;
	int owidth = (m_pEditorManager->m_pClipPlane->GetWidth() / 32) + 1;
	int oheight = (m_pEditorManager->m_pClipPlane->GetHeight() / 32) + 2;

	for(vector<Room*>::const_iterator it = rooms.begin(); it != rooms.end(); ++it)
	{
		// basically, these four variables are used to speed up rendering: they are either set as the entire screen or as 
		int startX = ((*it)->x1 > ostartX) ? ((*it)->x1) : (ostartX); // if x1 is bigger, than use x1, otherwise use ostartX
		int startY = ((*it)->y1 > ostartY) ? ((*it)->y1) : (ostartY); // same but w/ y

		int width = ((*it)->w < owidth) ? ((*it)->w) : (owidth);
		int height = ((*it)->h < oheight) ? ((*it)->h) : (oheight);
		
		/*if((*it)->w < owidth)
			if((*it)->x1 < ostartX)
				width = (*it)->w - (startX - ostartX);
			else
				width = (*it)->w;

		if((*it)->h < oheight)
			if((*it)->y1 < ostartY)
				height = (*it)->h - (startY - ostartY);
			else
				height = (*it)->h;*/

		/*for(int h = startY; h < startY + height; ++h)
			for(int w = startX; w < startX + width; ++w)
			{
				if(h-startY < (*it)->tiles.size() && w-startX < (*it)->tiles[0].size())
					for(int l = 0; l < (*it)->tiles[h-startY][w-startX].size(); ++l)
						Entity::RenderImage(w * TILE_DIMENSIONS, h * TILE_DIMENSIONS, (*it)->tiles[h-startY][w-startX][l], m_pEditorManager->m_pClipPlane);
				else
					Log->AddMessage("RoomGrid::Render attempted to access a bad index");
			}

	}

}*/